#ifndef __IDynVariable_H__
#define __IDynVariable_H__

//#include "rect.h"
//#include "SColor.h"
//#include "vector3d.h"
//#include "vector2d.h"
//#include <debug_new/debug_new.h>
#include "types.h"
#include "stream/IReader.h"
#include "stream/IWriter.h"
#include "StringUtils.h"
#include "stream/Serializable.h"


namespace lampe{

/***
* @class IDynVariable
* Реализует переменную динамического типа. Память выделяется только под переменную
* текущего типа. Некоторые методы не соответствующие текущему типу темнимение могут
* вернуть правельное значение. Например, сейчас в экземпляре класса IDynVariable
* хранится переменная типа s32, но если вызвать метод getString(), то вернётся
* строка, значением которой и будет то самое число.
* */

class IDynVariable:public virtual stream::Serializable{
public:
	//! тип переменной
	enum VariableType{
		VT_NONE=1,
		VT_STRING,
		VT_BOOL,
		VT_S32,
		VT_F32,
		VT_U32,
		VT_COLOR,
		VT_VECTOR2I,
		VT_VECTOR2F,
		VT_VECTOR3I,
		VT_VECTOR3F
	};
private:



	

	

	VariableType currentType;
	String*v_string;
	s32*v_s32;
	f32*v_f32;
	u32*v_u32;
	bool*v_bool;
	SColor*v_Color;
	Vector2di*v_vector2di;
	Vector2df*v_vector2df;
	Vector3di*v_vector3di;
	Vector3df*v_vector3df;

	void clear(){
		switch (currentType){
			case VT_NONE:
				return;
			case VT_STRING:
				delete v_string;
				v_string=0;
				return;
			case VT_BOOL:
				delete v_bool;
				v_bool=0;
				return;
			case VT_S32:
				delete v_s32;
				v_s32=0;
				return;
			case VT_F32:
				delete v_f32;
				v_f32=0;
				return;
			case VT_U32:
				delete v_u32;
				v_u32=0;
				return;
			case VT_COLOR:
				delete v_Color;
				v_Color=0;
				return;
			case VT_VECTOR2I:
				delete v_vector2di;
				v_vector2di=0;
				return;
			case VT_VECTOR2F:
				delete v_vector2df;
				v_vector2df=0;
				return;
			case VT_VECTOR3I:
				delete v_vector3di;
				v_vector3di=0;
				return;
			case VT_VECTOR3F:
				delete v_vector3df;
				v_vector3df=0;
				return;
		}
		return;
	}
public:
	IDynVariable(){
		v_string=0;
		v_s32=0;
		v_f32=0;
		v_u32=0;
		v_bool=0;
		v_Color=0;
		v_vector2di=0;
		v_vector2df=0;
		v_vector3di=0;
		v_vector3df=0;
		currentType=VT_NONE;
	}

	~IDynVariable(){
		clear();
	}

	bool isNone(){
		return currentType==VT_NONE;
	}

	u32 getU32(){
		if (currentType==VT_STRING){
			u32 decimal;
			sscanf(getString().c_str(),"%u",&decimal);
			return decimal;
		}
		if (currentType==VT_U32){
			return *v_u32;
		}
		if (currentType==VT_S32){
			return *v_s32;
		}
		if (currentType==VT_F32){
			return *v_f32;
		}
		if (currentType==VT_BOOL){
			if (*v_bool)
				return 1;
			else
				return 0;
		}
		return 0;
	}

	u32 getBool(){
		if (currentType==VT_STRING){
			String str=getString();
			for (u32 i=0;i<str.length();i++)
				str[i]=tolower(str[i]);
			return (str=="true")||(str=="1");
		}
		if (currentType==VT_U32){
			return (*v_u32)>0;
		}
		if (currentType==VT_S32){
			return (*v_s32)>0;
		}
		if (currentType==VT_F32){
			return (*v_f32)>0;
		}
		if (currentType==VT_BOOL){
			return *v_bool;
		}
		return false;
	}

	s32 getS32(){
		if (currentType==VT_STRING){
			return str::toI32(getString());
		}
		if (currentType==VT_U32){
			return *v_u32;
		}
		if (currentType==VT_S32){
			return *v_s32;
		}
		if (currentType==VT_F32){
			return *v_f32;
		}
		if (currentType==VT_BOOL){
			if (*v_bool)
				return 1;
			else
				return 0;
		}
		return 0;
	}

	String getString(){
		if (currentType==VT_STRING)
			return *v_string;

		if (currentType==VT_U32)
			return str::fromU32(*v_u32);

		if (currentType==VT_S32)
			return str::fromS32(*v_s32);

		if (currentType==VT_F32)
			return str::fromF32(*v_f32);

		if (currentType==VT_VECTOR2I)
			return String(str::fromS32((*v_vector2di).X)+";"+str::fromS32((*v_vector2di).Y));

		if (currentType==VT_VECTOR2F)
			return String(str::fromF32((*v_vector2df).X)+";"+str::fromF32((*v_vector2df).Y));

		if (currentType==VT_VECTOR3I)
			return String(str::fromS32((*v_vector3di).X)+";"+str::fromS32((*v_vector3di).Y)+";"+str::fromS32((*v_vector3di).Z));

		if (currentType==VT_VECTOR3F)
			return String(str::fromF32((*v_vector3df).X)+";"+str::fromF32((*v_vector3df).Y)+";"+str::fromF32((*v_vector3df).Z));


		if (currentType==VT_COLOR)
			return String(
					str::fromS32((*v_Color).getAlpha())+";"+
					str::fromS32((*v_Color).getRed())+";"+
					str::fromS32((*v_Color).getGreen())+";"+
					str::fromS32((*v_Color).getBlue()));
		if (currentType==VT_BOOL){
			if (*v_bool)
				return "true";
			else
				return "false";
		}
		return "";
	}

	f32 getF32(){
		if (currentType==VT_STRING){
			return str::toF32(getString());
		}
		if (currentType==VT_U32){
			return *v_u32;
		}
		if (currentType==VT_S32){
			return *v_s32;
		}
		if (currentType==VT_F32){
			return *v_f32;
		}
		if (currentType==VT_BOOL){
			if (*v_bool)
				return 1.0f;
			else
				return 0.0f;
		}
		return 0;
	}

	SColor getColor(){
		if (currentType==VT_STRING){
			LAMPE_VECTOR_VENDOR<String> list;
			str::split(getString(),&list,';');
			SColor res=SColor(0,0,0,0);
			for (u8 i=0;i<list.size();i++)
				if (i==0)
					res.setAlpha(str::toU32(list[0]));
				else
					if (i==1)
						res.setRed(str::toU32(list[1]));
					else
						if (i==2)
							res.setGreen(str::toU32(list[2]));
						else
							if (i==3)
								res.setBlue(str::toU32(list[3]));


			return res;
		}
		if (currentType==VT_COLOR){
			return *v_Color;
		}
		if (currentType==VT_BOOL){
			if (*v_bool)
				return SColor(255,255,255,255);
			else
				return SColor(0,0,0,0);
		}
		if (currentType==VT_U32){
			return SColor(*v_u32);
		}
		return SColor();
	}

	Vector2di getVector2di(){
		if (currentType==VT_STRING){
			LAMPE_VECTOR_VENDOR<String> list;
			str::split(getString(),&list,';');
			Vector2di res=Vector2di(0,0);
			for (u8 i=0;i<list.size();i++){
				if (i==0)
					res.X=str::toI32(list[0]);
				else
					if (i==1)
						res.Y=str::toI32(list[1]);
			}

			return res;
		}
			if (currentType==VT_VECTOR2I){
			return *v_vector2di;
		}
		if (currentType==VT_BOOL){
			if (*v_bool)
				return Vector2di(1,1);
			else
				return Vector2di(0,0);
		}
		return Vector2di(0,0);
	}

	Vector2df getVector2df(){
		if (currentType==VT_STRING){
			LAMPE_VECTOR_VENDOR<String> list;
			str::split(getString(),&list,';');
			Vector2df res=Vector2df(0,0);
			for (u8 i=0;i<list.size();i++)
				if (i==0)
					res.X=str::toF32(list[0]);
				else
					if (i==1)
						res.Y=str::toF32(list[1]);

			return res;
		}
		if (currentType==VT_VECTOR2F){
			return *v_vector2df;
		}
		if (currentType==VT_BOOL){
			if (*v_bool)
				return Vector2df(1.0f,1.0f);
			else
				return Vector2df(0.0f,0.0f);
		}
		return Vector2df(0.0f,0.0f);
	}

	Vector3di getVector3di(){
		if (currentType==VT_STRING){
			LAMPE_VECTOR_VENDOR<String> list;
			str::split(getString(),&list,';');
			Vector3di res=Vector3di(0,0,0);
			for (u8 i=0;i<list.size();i++)
				if (i==0)
					res.X=str::toI32(list[0]);
				else
					if (i==1)
						res.Y=str::toI32(list[1]);
					else
						if (i==2)
							res.Z=str::toI32(list[2]);


			return res;
		}
		if (currentType==VT_VECTOR3I){
			return *v_vector3di;
		}
		if (currentType==VT_BOOL){
			if (*v_bool)
				return Vector3di(1,1,1);
			else
				return Vector3di(0,0,0);
		}
		return Vector3di(0,0,0);
	}


	Vector3df getVector3df(){
		if (currentType==VT_STRING){
			LAMPE_VECTOR_VENDOR<String> list;
			str::split(getString(),&list,';');
			Vector3df res=Vector3df(0.0f,0.0f,0.0f);
			for (u8 i=0;i<list.size();i++){
				if (i==0)
					res.X=str::toF32(list[0]);
				else
					if (i==1)
						res.Y=str::toF32(list[1]);
					else
						if (i==2)
							res.Z=str::toF32(list[2]);
			}
			return res;
		}
		if (currentType==VT_VECTOR3F){
			return *v_vector3df;
		}
		if (currentType==VT_BOOL){
			if (*v_bool)
				return Vector3df(1.0f,1.0f,1.0f);
			else
				return Vector3df(0.0f,0.0f,0.0f);
		}
		return Vector3df(0.0f,0.0f,0.0f);
	}

	VariableType getType(){
		return currentType;
	}

	void setNone(){
		clear();
		currentType=VT_NONE;
	}

	void setU32(u32 value){
		clear();
		currentType=VT_U32;
		v_u32=new u32();
		*v_u32=value;
	}

	void setS32(s32 value){
		clear();
		currentType=VT_S32;
		v_s32=new s32();
		*v_s32=value;
	}

	void setString(String value){
		clear();
		currentType=VT_STRING;
		v_string=new String();
		*v_string=value;
	}

	void setF32(f32 value){
		clear();
		currentType=VT_F32;
		v_f32=new f32();
		*v_f32=value;
	}

	void setColor(SColor value){
		clear();
		currentType=VT_COLOR;
		v_Color=new SColor();
		*v_Color=value;
	}

	void setVector2di(Vector2di value){
		clear();
		currentType=VT_VECTOR2I;
		v_vector2di=new Vector2di();
		*v_vector2di=value;
	}

	void setVector2df(Vector2df value){
		clear();
		currentType=VT_VECTOR2F;
		v_vector2df=new Vector2df();
		*v_vector2df=value;
	}

	void setVector3di(Vector3di value){
		clear();
		currentType=VT_VECTOR3I;
		v_vector3di=new Vector3di();
		*v_vector3di=value;
	}

	void setVector3df(Vector3df value){
		clear();
		currentType=VT_VECTOR3I;
		v_vector3df=new Vector3df();
		*v_vector3df=value;
	}


	void setBool(bool value){
		clear();
		currentType=VT_BOOL;
		v_bool=new bool();
		*v_bool=value;
	}

	IDynVariable& operator=(const bool& value){
		setBool(value);
		return *this;
	}

	IDynVariable& operator=(const s32& value){
		setS32(value);
		return *this;
	}

	IDynVariable& operator=(const f32& value){
		setF32(value);
		return *this;
	}

	IDynVariable& operator=(const u32& value){
		setU32(value);
		return *this;
	}

	IDynVariable& operator=(const String& value){
		setString(value);
		return *this;
	}

	IDynVariable& operator=(const SColor& value){
		setColor(value);
		return *this;
	}

	IDynVariable& operator=(const Vector2di& value){
		setVector2di(value);
		return *this;
	}

	IDynVariable& operator=(const Vector2df& value){
		setVector2df(value);
		return *this;
	}

	IDynVariable& operator=(const Vector3di& value){
		setVector3di(value);
		return *this;
	}

	IDynVariable& operator=(const Vector3df& value){
		setVector3df(value);
		return *this;
	}

    virtual void deserialization(stream::IReader*reader){
		VariableType type=(VariableType)reader->readU8();
		switch (type){
				case VT_NONE:
					return;
				case VT_STRING:
					setString(reader->readStringc());
					return;
				case VT_BOOL:
					setBool(reader->readU8()==1);
					return;
				case VT_S32:
					setS32(reader->readS32());
					return;
				case VT_F32:
					setF32(reader->readF32());
					return;
				case VT_U32:
					setU32(reader->readU32());
					return;
				case VT_COLOR:
					setColor(reader->readU32());
					return;
				case VT_VECTOR2I:
					setVector2di(lampe::Vector2di(reader->readS32(),reader->readS32()));
					return;
				case VT_VECTOR2F:
					setVector2df(lampe::Vector2df(reader->readF32(),reader->readF32()));
					return;
				case VT_VECTOR3I:
					setVector3di(lampe::Vector3di(reader->readS32(),reader->readS32(),reader->readS32()));
					return;
				case VT_VECTOR3F:
					setVector3df(lampe::Vector3df(reader->readF32(),reader->readF32(),reader->readF32()));
					return;
				}
	}

    virtual void serialization(stream::IWriter*writer){
		writer->writeU8(currentType);
		switch (currentType){
		case VT_NONE:
			return;
		case VT_STRING:
			writer->writeStringc(*v_string);
			return;
		case VT_BOOL:
			writer->writeU8((*v_bool)?1:0);
			return;
		case VT_S32:
			writer->writeS32(*v_s32);
			return;
		case VT_F32:
			writer->writeF32(*v_f32);
			return;
		case VT_U32:
			writer->writeU32(*v_u32);
			return;
		case VT_COLOR:
			writer->writeU32(v_Color->color);
			return;
		case VT_VECTOR2I:
			writer->writeS32(v_vector2di->X);
			writer->writeS32(v_vector2di->Y);
			return;
		case VT_VECTOR2F:
			writer->writeF32(v_vector2df->X);
			writer->writeF32(v_vector2df->Y);
			return;
		case VT_VECTOR3I:
			writer->writeS32(v_vector3di->X);
			writer->writeS32(v_vector3di->Y);
			writer->writeS32(v_vector3di->Z);
			return;
		case VT_VECTOR3F:
			writer->writeF32(v_vector3df->X);
			writer->writeF32(v_vector3df->Y);
			writer->writeF32(v_vector3df->Z);
			return;
		}
	}
};

}//namespace lampe

#endif
